﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WatiN.Core;
using WatiN.Core.Constraints;
using WatiN.Core.Native.Windows;
using WatiN.Core.UtilityClasses;

namespace WebAutomation.Browsers.IE
{
    public class IEBrowser : WebBrowserObject
    {
        private WatiN.Core.IE ie;
        public IEBrowser(int processId=0)
        {
            if (processId > 0)
            {
                
                var hwnd = ParseIntPtr(processId.ToString());
                ie = WatiN.Core.IE.AttachTo<WatiN.Core.IE>(Find.By("hwnd", handle => !handle.Equals(hwnd)));
            }
            else
            {
                ie = new WatiN.Core.IE();
            }
        }

        public override object GetWebBrowserObject()
        {
            return ie;
        }

        static IntPtr ParseIntPtr(string s)
        {
            s = s.Replace("0x", "");
            return (IntPtr)int.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier);
        }



        public override int ProcessID
        {
            get { return ie.ProcessID; }
        }

        public override void ButtonWaitUntilExists(Constraint find)
        {

            ie.Button(find).WaitUntilExists();
        }

        public override void DivWaitUntilAttributeValue(string divID,string attributeName,string expectedValue)
        {
            ie.Div(divID).WaitUntil(attributeName, expectedValue);
        }

        public override void WaitForComplete()
        {

            ie.WaitForComplete();
        }

        public override object Div(Constraint find)
        {
            object returnValue = null;
            WatiN.Core.Div Div = ie.Div(find);
            returnValue = !Div.Exists ? null : Div;
            return returnValue;
        }

        public override object DomContainer()
        {
            return ie.DomContainer;
        }

        public override void CaptureWebPageAsImage(string imageFileName, string imageQualityString, int imageQuality)
        {
            using (FileStream fStr = new FileStream(imageFileName, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                CaptureWebPage cwp = new CaptureWebPage(this.ie.DomContainer);
                cwp.CaptureWebPageToFile(fStr, CaptureWebPage.ImageCodecs.Jpeg, true, false, 100, imageQuality);
                fStr.Close();
            } 
        }

        public override ElementProperties Element(Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            elementProperties.Element = ie.Element(find);
            elementProperties.Exists = ie.Element(find).Exists;
            return elementProperties;
        }

        public override ElementProperties Element()
        {
            WatiN.Core.Element element = null;
            ElementProperties elementProperties = new ElementProperties();
            elementProperties.Element = element;
            return new ElementProperties();
        }

        public override Dictionary<int,object> Frames()
        {
            Dictionary<int, object> list = new Dictionary<int, object>();
            int i = 0;
            try
            {
                foreach (var items in ie.Frames.ToList())
                {
                    list.Add(i, items);
                    i++;
                }
            }catch
            {
            }
            return list;
        }

        public override void WaitForCompleteIFrame(int iframeIndex,int secondsToWait)
        {
            ie.Frames[iframeIndex].DomContainer.WaitForComplete(secondsToWait);
        }


        public override ElementProperties ElementIFrame(int iframeIndex, string idOrNameOrClassOrValue)
        {
            WatiN.Core.Element element = null;
            ElementProperties elementProperties = new ElementProperties();
            element = ie.Frames[iframeIndex].Element(Find.ByName(idOrNameOrClassOrValue));
            if (!element.Exists)
            {
                element = ie.Frames[iframeIndex].Element(Find.ById(idOrNameOrClassOrValue));
            }
            if (!element.Exists)
            {
                element = ie.Frames[iframeIndex].Element(Find.ByClass(idOrNameOrClassOrValue));
            }
            if (!element.Exists)
            {
                element = ie.Frames[iframeIndex].Element(Find.ByValue(idOrNameOrClassOrValue));
            }
            elementProperties.Element = element;
            if (!element.Exists)
            {
                elementProperties.Exists = false;
            }else
            {
                elementProperties.Exists = true;
            }
            return elementProperties;
        }

        public override void GoTo(string url)
        {
            ie.GoTo(url);
        }

        public override string Html()
        {
            return  ie.Html;
        }

        public override string HtmlIFrame(int iframeIndex)
        {
            return ie.Frames[iframeIndex].Html;
        }

        public override ElementProperties Link(string attributeValue)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.Link link =
                    ie.Links.FirstOrDefault(
                        i =>
                        (i.GetAttributeValue("id") == attributeValue) ||
                        (i.GetAttributeValue("name") == attributeValue) ||
                        (i.ClassName == attributeValue) ||
                        (i.GetAttributeValue("value") == attributeValue)||
                        i.InnerHtml == attributeValue
                        
                        );
            if (link != null)
            {
                if (link.Exists)
                {
                    elementProperties.Element = link;
                    elementProperties.Exists = true;
                }
            }

            return elementProperties;
        }

        public override Dictionary<int, object> FrameLinks(int iframeIndex)
        {
            Dictionary<int, object> list = new Dictionary<int, object>();
            int i = 0;
            foreach (var items in ie.Frames[iframeIndex].Links)
            {
                list.Add(i, items);
                i++;
            }

            return list;
        }

        public override string GetIFrameLinkAttributeValue(int iframeIndex,int linkIndex,string attributeName)
        {
            return ie.Frames[iframeIndex].Links[linkIndex].GetAttributeValue(attributeName);
        }

        public override string GetIFrameLinkClassName(int iframeIndex, int linkIndex)
        {
            return ie.Frames[iframeIndex].Links[linkIndex].ClassName;
        }

        public override void RunScript(string scriptToRun)
        {
            ie.RunScript(scriptToRun);
        }

        public override ElementProperties SelectList(Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.SelectList selectList = ie.SelectList(find);
            if(selectList.Exists)
            {
                elementProperties.Element = selectList;
                elementProperties.Exists = true;
            }
    
            return elementProperties;
        }

        public override ElementProperties RadioButton(Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.RadioButton selectList = ie.RadioButton(find);
            if (selectList.Exists)
            {
                elementProperties.Element = selectList;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override ElementProperties CheckBox(Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.CheckBox checkBox = ie.CheckBox(find);
            if (checkBox.Exists)
            {
                elementProperties.Element = checkBox;
                elementProperties.Exists = true;
            }else
            {
                string[] findByArray = find.ToString().Replace("Attribute ", "").Replace(" equals ", "^").Split('^');
                string findBy = findByArray[0].Replace("'", "");
                string findValue = findByArray[1].Replace("'", "");

                foreach(var item in ie.CheckBoxes)
                {
                    string name = item.Name;
                    if(name==findValue)
                    {
                        checkBox = item;
                        break;
                    }
                }

                if (checkBox.Exists)
                {
                    elementProperties.Element = checkBox;
                    elementProperties.Exists = true;
                }else
                {
                    foreach (var item in ie.CheckBoxes)
                    {
                        string id = item.Id;
                        if (id == findValue)
                        {
                            checkBox = item;
                            break;
                        }
                    }

                }
                if (checkBox.Exists)
                {
                    elementProperties.Element = checkBox;
                    elementProperties.Exists = true;
                }


            }

            return elementProperties;
        }


        public override ElementProperties GetLinkByText(string text, int index)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.Link linkField = null;
           
            int count = 1;
            bool doesExist = false;
            foreach(var item in this.ie.Links)
            {

                if (item.Text.ToLower() == text.ToLower())
                {
                    
                    if (index == count)
                    {
                        doesExist = true;
                        linkField = item;
                        break;
                    }
                    count++;
                }
            }

            //check iframes
            if (!doesExist)
            {
                count = 1;
                foreach (var itemFrame in this.ie.Frames)
                {
                    
                    foreach (var item in itemFrame.Links)
                    {
                        if (item.Text.ToLower() == text.ToLower())
                        {
                            
                            if (index == count)
                            {
                                doesExist = true;
                                linkField = item;
                                break;
                            }

                            count++;
                        }
                        
                    }
                    if(doesExist)
                    {
                        break;
                    }
                }

            }

            elementProperties.Element = linkField;
            elementProperties.Exists = doesExist;

            return elementProperties;
        }


        public override void RadioButtonCheck(object radioButton, string valueOrId)
        {
            WatiN.Core.RadioButton radio = (WatiN.Core.RadioButton)radioButton;
            radio.Checked = true;
        }

        public override void CheckBoxCheck(object checkBox, string valueOrId)
        {
            WatiN.Core.CheckBox check = (WatiN.Core.CheckBox) checkBox;
            check.Checked = valueOrId.ToLower() == "true" || valueOrId.ToLower()=="on";
        }

        public override void ElementClick(object element)
        {
            WatiN.Core.Element elem = (WatiN.Core.Element)element;
            elem.Click();
        }

        public override bool SelectListSelect(object element, string selectListValue)
        {
            bool returnValue = false;
            string error = "";
            bool isError = true;
            try
            {
                WatiN.Core.SelectList selectListTest = (WatiN.Core.SelectList)element;
                isError = false;
            }catch(Exception ex)
            {
                error = ex.Message;
            }

            if (isError)
            {
                WatiN.Core.Element el = (Element)element;
                el.SetAttributeValue("value", selectListValue);
                //el.Click();
                try
                {
                    if (!string.IsNullOrEmpty(el.GetAttributeValue("onchange")))
                    {
                        el.FireEvent("onchange");
                    }
                }catch(Exception ex)
                {
                    
                }
                returnValue = true;
            }
            else
            {
                WatiN.Core.SelectList selectList = (WatiN.Core.SelectList) element;
                bool isFound = false;
                int i = 0;
                foreach (var item in selectList.Options)
                {
                    if (item.Value.ToLower() == selectListValue.ToLower().Trim())
                    {
                        selectList.Options[i].Select();
                        selectList.Options[i].Click();
                        returnValue = true;
                        isFound = true;
                        break;
                    }
                    i++;
                }
               
            }

            return returnValue;
           
        }

        public override void ShowWindow(NativeMethods.WindowShowStyle windowShowStyle)
        {
            ie.ShowWindow(windowShowStyle);

        }

        public override ElementProperties TextField(Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.TextField textField = ie.TextField(find);
            if (textField.Exists)
            {
                elementProperties.Element = textField;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override ElementProperties TextFieldIFrame(int iframeIndex,Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.TextField textField = ie.Frames[iframeIndex].TextField(find);

            if (textField.Exists)
            {
                elementProperties.Element = textField;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void TypeText(object textField,string textValueToType,WebBrowserObject webBrowserObject)
        {
            //WatiN.Core.TextField txt = (WatiN.Core.TextField)textField;
            //txt.TypeText(textValueToType);

            var ele = (Element)textField;
            if (ele.GetAttributeValue("readOnly") == "True" || ele.GetAttributeValue("readOnly") == "true")
            {
                string eleId = ele.GetAttributeValue("id");
                string javaScriptToRun = "document.getElementById('" + eleId + "').value='" + textValueToType + "'";

                webBrowserObject.RunScript(javaScriptToRun);

            }
            else
            {
                WatiN.Core.TextField txt = (WatiN.Core.TextField)textField;
                txt.TypeText(textValueToType);
            }
        }

        public override ElementProperties Button(Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.Button btn = ie.Button(find);

            if (btn.Exists)
            {
                elementProperties.Element = btn;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override ElementProperties ButtonIFrame(int iframeIndex,Constraint find)
        {
            ElementProperties elementProperties = new ElementProperties();
            WatiN.Core.Button btn = ie.Frames[iframeIndex].Button(find);

            if (btn.Exists)
            {
                elementProperties.Element = btn;
                elementProperties.Exists = true;
            }

            return elementProperties;
        }

        public override void ButtonClick(object buttonField)
        {
            WatiN.Core.Button btn = (WatiN.Core.Button)buttonField;
            btn.Click();
        }

        public override void ButtonMouseDown(object buttonField)
        {
            WatiN.Core.Button btn = (WatiN.Core.Button)buttonField;
            btn.MouseDown();
        }

        public override void ButtonMouseUp(object buttonField)
        {
            WatiN.Core.Button btn = (WatiN.Core.Button)buttonField;
            btn.MouseUp();
        }

        public override string GetLinkAttributeValue(object link,string attributeToGet)
        {
            WatiN.Core.Link lnk = (WatiN.Core.Link)link;
            return lnk.GetAttributeValue(attributeToGet);
        }

        public override void LinkClick(object link)
        {
            WatiN.Core.Link lnk = (WatiN.Core.Link)link;
            lnk.Click();
        }

        private string _getElementAttribute(WatiN.Core.Element element,string attributeName)
        {
            string returnValue = "";
            try
            {
                returnValue = element.GetAttributeValue(attributeName);
            }catch(Exception ex)
            {
                
            }

            return returnValue;

        }

        public override Dictionary<int, ElementProperties> Elements()
        {
            Dictionary<int, ElementProperties> list = new Dictionary<int, ElementProperties>();
            int i = 0;
            foreach (var items in ie.Elements)
            {
                ElementProperties elementProperties = new ElementProperties();
                elementProperties.Exists = true;
                elementProperties.Element = items;
                elementProperties.ElementType = items.GetType().ToString();
                elementProperties.ElementHTMLType = items.TagName;

                elementProperties.ElementAttributes = new Dictionary<string, string>();
                elementProperties.ElementAttributes.Add("Type", _getElementAttribute(items,"type"));
                elementProperties.ElementAttributes.Add("Name", _getElementAttribute(items, "name"));
                elementProperties.ElementAttributes.Add("ID", _getElementAttribute(items, "id"));
                elementProperties.ElementAttributes.Add("ClassName", items.ClassName);
                elementProperties.ElementAttributes.Add("Style", items.Style.ToString());
                elementProperties.ElementAttributes.Add("Value", _getElementAttribute(items, "value"));
                elementProperties.ElementAttributes.Add("Click", _getElementAttribute(items, "click"));
                elementProperties.ElementAttributes.Add("Change", _getElementAttribute(items, "change"));
                elementProperties.ElementAttributes.Add("Href", _getElementAttribute(items, "href"));

                list.Add(i, elementProperties);
                i++;
            }

            return list;
        }

        public override string GetIFrameAttributeValue(int iframeIndex, string attributeName)
        {
            return ie.Frames[iframeIndex].GetAttributeValue(attributeName);
        }

        public override bool ElementExist(object element)
        {
            bool returnValue = false;
            WatiN.Core.Element elem = (WatiN.Core.Element)element;
            if (elem!=null)
            {
                returnValue = elem.Exists;
            }
            return returnValue;
        }

        public override bool Dispose()
        {
            return true;
        }

        public override void WinFormType(int winHandle, string textBoxId, string textToType)
        {
            throw new NotImplementedException();
        }

        public override void KeyPressEnter(object textField, string keyName, WebBrowserObject browserObject)
        {
            WatiN.Core.Element elem = (WatiN.Core.Element)textField;
            elem.KeyPress((char)Keys.Enter);        
        }

        public override void Refresh(string keys)
        {
            ie.Refresh();

        }
    }
}
